package com.csot.ry.service.impl;

import cn.hutool.core.map.BiMap;
import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.csot.common.core.domain.entity.SysRole;
import com.csot.common.core.domain.entity.SysUser;
import com.csot.common.core.text.Convert;
import com.csot.common.exception.ServiceException;
import com.csot.common.utils.DateUtils;
import com.csot.common.utils.SecurityUtils;
import com.csot.common.utils.StringUtils;
import com.csot.ry.domain.TTotalSegment;
import com.csot.ry.mapper.TTotalSegmentMapper;
import com.csot.ry.service.ITTotalSegmentService;
import com.csot.ry.util.CacheKitUtil;
import com.csot.ry.util.UserUtils;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.ehcache.CacheKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 省级ip段Service业务层处理
 *
 * @author 刘沙
 * @date 2022-05-31
 */
@Service
public class TTotalSegmentServiceImpl implements ITTotalSegmentService {
    private static final Logger log = LoggerFactory.getLogger(TTotalSegmentServiceImpl.class);

    private static BiMap<String, String> ip_type = CacheKit.get("dict-data", "ip_type");
    private static BiMap<String, String> ip_city = CacheKit.get("dict-data", "ip_city");
    private static BiMap<String, String> ip_status = CacheKit.get("dict-data", "ip_status");

    private static String ERRORINFO = "很抱歉，导入失败！";
    @Autowired
    private TTotalSegmentMapper tTotalSegmentMapper;

    /**
     * 查询省级ip段
     *
     * @param id 省级ip段主键
     * @return 省级ip段
     */
    @Override
    public TTotalSegment selectTTotalSegmentById(Long id) {
        return tTotalSegmentMapper.selectTTotalSegmentById(id);
    }

    /**
     * 查询省级ip段列表
     *
     * @param tTotalSegment 省级ip段
     * @return 省级ip段
     */
    @Override
    public List<TTotalSegment> selectTTotalSegmentList(TTotalSegment tTotalSegment) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        List<SysRole> roles = user.getRoles();
        List<String> roleKeys = roles.stream().map(r -> {
            return "'" + r.getRoleKey() + "'";
        }).collect(Collectors.toList());
        String iptype = StringUtils.join(roleKeys, ",");
        if (iptype.indexOf("admin") > -1) {
            if (StrUtil.isNotEmpty(tTotalSegment.getIpType())) {
                tTotalSegment.setIpType("'" + tTotalSegment.getIpType() + "'");
            }
        } else if (StrUtil.isNotEmpty(tTotalSegment.getIpType())) {
            if (iptype.indexOf(tTotalSegment.getIpType()) < 0) {
                throw new IllegalArgumentException("没有此网络类型的权限！");
            } else {
                tTotalSegment.setIpType("'" + tTotalSegment.getIpType() + "'");
            }
        } else {
            tTotalSegment.setIpType(iptype);
        }
        Long deptid = user.getDeptId();
        if (iptype.indexOf("admin") > -1) {

        } else if (deptid != 100) {
            tTotalSegment.setIpCity(CacheKitUtil.ip_dept.get(user.getDept().getParentId() + ""));
        }
        try {
            if (StrUtil.isNotEmpty(tTotalSegment.getIpStart())) {
                tTotalSegment.setIpStartI(NetUtil.ipv4ToLong(tTotalSegment.getIpStart().trim()));
            }
            if (StrUtil.isNotEmpty(tTotalSegment.getIpEnd())) {
                tTotalSegment.setIpEndI(NetUtil.ipv4ToLong(tTotalSegment.getIpEnd().trim()));
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new IllegalArgumentException("数据格式不正确！");
        }
        return tTotalSegmentMapper.selectTTotalSegmentList(tTotalSegment);
    }

    /**
     * 新增省级ip段
     *
     * @param tTotalSegment 省级ip段
     * @return 结果
     */
    @Override
    public int insertTTotalSegment(TTotalSegment tTotalSegment) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        Long deptid = user.getDeptId();
        if (!"admin".equals(user.getUserName())) {
            if (deptid != 100 && StrUtil.isNotEmpty(tTotalSegment.getIpCity())
                    && !tTotalSegment.getIpCity().equals(CacheKitUtil.ip_dept.get(user.getDept().getParentId() + ""))) {
                throw new ServiceException("不能创建其他地市的信息");
            }

            if (!UserUtils.isRole(tTotalSegment.getIpType())) {
                throw new ServiceException("没有该类型：" + CacheKitUtil.ip_type.get(tTotalSegment.getIpType()) + " 权限");
            }
        }
        Record record = Db.findFirst(
                "SELECT 1 FROM t_total_segment WHERE (? between ip_start_i AND ip_end_i "
                        + "OR ? between ip_start_i AND ip_end_i ) AND ip_type = ? limit 1",
                tTotalSegment.getIpStartI(), tTotalSegment.getIpEndI(),
                CacheKitUtil.ip_type.getKey(tTotalSegment.getIpType()));

        if (record != null) {
            throw new IllegalArgumentException("插入失败：此地址范围已存在");
        }

        tTotalSegment.setCreateTime(DateUtils.getNowDate());
        tTotalSegment.setIpStartI(NetUtil.ipv4ToLong(tTotalSegment.getIpStart().trim()));
        tTotalSegment.setIpEndI(NetUtil.ipv4ToLong(tTotalSegment.getIpEnd().trim()));
        if (tTotalSegment.getIpEndI() < tTotalSegment.getIpStartI()) {
            throw new IllegalArgumentException("起始地址不能大于终止地址。");
        }
        return tTotalSegmentMapper.insertTTotalSegment(tTotalSegment);
    }

    /**
     * 修改省级ip段
     *
     * @param tTotalSegment 省级ip段
     * @return 结果
     */
    @Override
    @Transactional
    public int updateTTotalSegment(TTotalSegment tTotalSegment) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        Long deptid = user.getDeptId();
        if (!"admin".equals(user.getUserName())) {
            if (deptid != 100 && StrUtil.isNotEmpty(tTotalSegment.getIpCity())
                    && !tTotalSegment.getIpCity().equals(CacheKitUtil.ip_dept.get(user.getDept().getParentId() + ""))) {
                throw new ServiceException("不能修改其他地市的信息");
            }
        }
        // 0、获取原来的数据
        TTotalSegment tTotalSegmentOld = this.selectTTotalSegmentById(tTotalSegment.getId());
        // 修改只能在原段内进行
        long newIpStartI = NetUtil.ipv4ToLong(tTotalSegment.getIpStart().trim());
        long newIpEndI = NetUtil.ipv4ToLong(tTotalSegment.getIpEnd().trim());
        if (newIpEndI < newIpStartI) {
            throw new ServiceException("终止IP不能小于起始IP！");
        }
        // 1、验证是否可以更新

        if (tTotalSegmentOld.getIpStartI() > newIpStartI || tTotalSegmentOld.getIpEndI() < newIpEndI) {
            throw new ServiceException("始止IP不能在原IP段之外！");
        }
        List<Record> citySegmentList = Db.find(
                "SELECT 1 FROM t_city_segment " + " WHERE (? between ip_start_i AND ip_end_i "
                        + " OR ? between ip_start_i AND ip_end_i ) " + " AND ip_type = ? ",
                newIpStartI, newIpEndI, tTotalSegment.getIpType());
        if (citySegmentList.size() > 0) {
            // 子表已经存在
            throw new ServiceException("地市已经使用数据，不能更新！");
        }
        if (tTotalSegmentOld.getIpStartI() == newIpStartI && tTotalSegmentOld.getIpEndI() > newIpEndI) {
//            TTotalSegment tTotalSegmentNew = ObjectUtil.clone(tTotalSegmentOld);
            TTotalSegment tTotalSegmentNew = getTotalSegmentByOld(tTotalSegmentOld);
            tTotalSegmentNew.setIpStartI(newIpEndI + 1);
            tTotalSegmentNew.setIpStart(NetUtil.longToIpv4(newIpEndI + 1));
            tTotalSegment.setIpEndI(newIpEndI);
            tTotalSegmentNew.setId(null);
            this.insertTTotalSegment(tTotalSegmentNew);
        } else if (tTotalSegmentOld.getIpStartI() < newIpStartI && tTotalSegmentOld.getIpEndI() == newIpEndI) {
//            TTotalSegment tTotalSegmentNew = ObjectUtil.clone(tTotalSegmentOld);
            TTotalSegment tTotalSegmentNew = getTotalSegmentByOld(tTotalSegmentOld);
            tTotalSegmentNew.setIpEndI(newIpStartI - 1);
            tTotalSegmentNew.setIpEnd(NetUtil.longToIpv4(newIpStartI - 1));
            tTotalSegment.setIpStartI(newIpStartI);
            tTotalSegmentNew.setId(null);
            this.insertTTotalSegment(tTotalSegmentNew);
        } else if (tTotalSegmentOld.getIpStartI() < newIpStartI && tTotalSegmentOld.getIpEndI() > newIpEndI) {
//            TTotalSegment tTotalSegmentNew1 = ObjectUtil.clone(tTotalSegmentOld);
            TTotalSegment tTotalSegmentNew1 = getTotalSegmentByOld(tTotalSegmentOld);
            tTotalSegmentNew1.setIpEndI(newIpStartI - 1);
            tTotalSegmentNew1.setIpEnd(NetUtil.longToIpv4(newIpStartI - 1));
            tTotalSegmentNew1.setId(null);
            this.insertTTotalSegment(tTotalSegmentNew1);
//            TTotalSegment tTotalSegmentNew2 = ObjectUtil.clone(tTotalSegmentOld);
            TTotalSegment tTotalSegmentNew2 = getTotalSegmentByOld(tTotalSegmentOld);
            tTotalSegmentNew2.setIpStartI(newIpEndI + 1);
            tTotalSegmentNew2.setIpStart(NetUtil.longToIpv4(newIpEndI + 1));
            tTotalSegmentNew2.setId(null);
            this.insertTTotalSegment(tTotalSegmentNew2);
            tTotalSegment.setIpEndI(newIpEndI);
            tTotalSegment.setIpStartI(newIpStartI);
        }
        tTotalSegment.setUpdateTime(DateUtils.getNowDate());
//        tTotalSegment.setIpType(ip_type.getKey(tTotalSegment.getIpType()));
        return tTotalSegmentMapper.updateTTotalSegment(tTotalSegment);
    }

    // 克隆没好用，只好写一次了
    private TTotalSegment getTotalSegmentByOld(TTotalSegment told) {
        TTotalSegment tnew = new TTotalSegment();
        tnew.setIpStart(told.getIpStart().trim());
        tnew.setIpStartI(told.getIpStartI());
        tnew.setIpEnd(told.getIpEnd().trim());
        tnew.setIpEndI(told.getIpEndI());
        tnew.setIpType(told.getIpType());
        tnew.setIpCity(told.getIpCity());
        tnew.setIpUser(told.getIpUser());
        tnew.setIpStatus(told.getIpStatus());
        tnew.setIpManagement(told.getIpManagement());
        tnew.setCreateBy(told.getCreateBy());
        tnew.setCreateTime(told.getCreateTime());
        tnew.setRemark(told.getRemark());
        return tnew;
    }

    /**
     * 批量删除省级ip段
     *
     * @param ids 需要删除的省级ip段主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteTTotalSegmentByIds(Long[] ids) {
        List<Record> citySegmentList = Db
                .find("SELECT b.*,c.* FROM " + "(SELECT ip_start_i,ip_end_i FROM t_total_segment WHERE id IN ("
                        + ArrayUtil.join(ids, ",") + ")  ) b \n" + ",(SELECT a.ip_address_i from t_city_ip a) c\n"
                        + " WHERE c.ip_address_i BETWEEN b.ip_start_i AND b.ip_end_i");

        if (citySegmentList.size() > 0) {
            // 子表已经存在
            throw new ServiceException("地市已经使用数据，不能删除！");
        }
        Db.delete("DELETE FROM  t_total_ip WHERE ip_segment_id IN (" + ArrayUtil.join(ids, ",") + ")");
        return tTotalSegmentMapper.deleteTTotalSegmentByIds(ids);
    }

    /**
     * 删除省级ip段信息
     *
     * @param id 省级ip段主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteTTotalSegmentById(Long id) {
        List<Record> citySegmentList = Db
                .find("SELECT b.*,c.* FROM " + "(SELECT ip_start_i,ip_end_i FROM t_total_segment WHERE id =?  ) b \n"
                        + ",(SELECT a.ip_address_i from t_city_ip a) c\n"
                        + " WHERE c.ip_address_i BETWEEN b.ip_start_i AND b.ip_end_i", id);

        if (citySegmentList.size() > 0) {
            // 子表已经存在
            throw new ServiceException("地市已经使用数据，不能删除！");
        }
        Db.delete("DELETE FROM  t_total_ip WHERE ip_segment_id in = ", id);
        return tTotalSegmentMapper.deleteTTotalSegmentById(id);
    }

    /**
     * 导入全量地址段管理数据
     *
     * @param tTotalSegmentList 全量地址段管理列表
     * @param isUpdateSupport   是否更新支持，如果已存在，则进行更新数据
     * @param user              操作用户
     * @return 结果
     */
    @Override
    @Transactional
    public synchronized int importTotalSegment(List<TTotalSegment> tTotalSegmentList, Boolean isUpdateSupport,
                                               SysUser user) {
        int successNum = 0;
        int failureNum = 0;
        StringBuilder failureMsg = new StringBuilder();
        if (StringUtils.isNull(tTotalSegmentList) || tTotalSegmentList.size() == 0) {
            throw new ServiceException(ERRORINFO + "<br/>导入全量地址段数据不能为空！");
        }
        // 转数据并验证
        List<TTotalSegment> totalSegmentList = getTotalSegmentList(tTotalSegmentList, user);
        try {
            // 验证Excel是否有重叠
            checkTotalSegmentIsRepeat(totalSegmentList);
        } catch (IllegalArgumentException e) {
            log.error(e.getMessage());
            throw e;
        }
        for (int i = 0; i < totalSegmentList.size(); i++) {
            TTotalSegment tTotalSegment = totalSegmentList.get(i);
            try {
                List<Record> totalSegment = Db.find(
                        "SELECT 1 FROM t_total_segment " + "WHERE (? between ip_start_i AND ip_end_i "
                                + "OR ? between ip_start_i AND ip_end_i )" + "AND ip_type = ? ",
                        tTotalSegment.getIpStartI(), tTotalSegment.getIpEndI(), tTotalSegment.getIpType());
                if (StringUtils.isNotEmpty(totalSegment)) {
                    failureNum++;
                    failureMsg.append("<br/>第" + (i + 2) + "行，起始地址 " + tTotalSegment.getIpStart() + "、终止地址 "
                            + tTotalSegment.getIpEnd() + " 已存在");
                    continue;
                }

                totalSegment = Db.queryFirst("select id from t_total_segment where (( ip_start_i between ? and ? ) or ( ip_end_i between ? and ? )) and ip_type = ? ",
                        tTotalSegment.getIpStartI(), tTotalSegment.getIpEndI(), tTotalSegment.getIpStartI(), tTotalSegment.getIpEndI(), tTotalSegment.getIpType());
                if (StringUtils.isNotEmpty(totalSegment)) {
                    failureNum++;
                    failureMsg.append("<br/>第" + (i + 2) + "行，起始地址 " + tTotalSegment.getIpStart() + "、终止地址 "
                            + tTotalSegment.getIpEnd() + " 已存在");
                    continue;
                }

                this.insertTTotalSegment(tTotalSegment);
                successNum++;

            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + (i + 2) + "、开始地址 " + tTotalSegment.getIpStart() + " 导入失败：";
                failureMsg.append(msg);
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        }
        return successNum;
    }

    // 验证传进来的数据是否有重复
    private String checkTotalSegmentIsRepeat(List<TTotalSegment> totalSegmentList) {
        TTotalSegment tTotalSegment_i = null;
        TTotalSegment tTotalSegment_j = null;
        for (int i = 0; i < totalSegmentList.size() - 1; i++) {
            tTotalSegment_i = totalSegmentList.get(i);
            if (tTotalSegment_i.getIpEndI() < tTotalSegment_i.getIpStartI()) {
                throw new IllegalArgumentException(ERRORINFO + "<br/> 第" + (i + 2) + "行， 起始地址不能大于终止地址。");
            }
            for (int j = i + 1; j < totalSegmentList.size(); j++) {
                tTotalSegment_j = totalSegmentList.get(j);
                if (tTotalSegment_i.getIpCity().equals(tTotalSegment_j.getIpCity()) &&
                        ((tTotalSegment_i.getIpStartI() >= tTotalSegment_j.getIpStartI()
                                && tTotalSegment_i.getIpStartI() <= tTotalSegment_j.getIpEndI())
                                || (tTotalSegment_i.getIpEndI() >= tTotalSegment_j.getIpStartI()
                                && tTotalSegment_i.getIpEndI() <= tTotalSegment_j.getIpEndI())
                                || (tTotalSegment_j.getIpEndI() >= tTotalSegment_i.getIpStartI()
                                && tTotalSegment_j.getIpEndI() <= tTotalSegment_i.getIpEndI())
                                || (tTotalSegment_j.getIpStartI() >= tTotalSegment_i.getIpStartI()
                                && tTotalSegment_j.getIpStartI() <= tTotalSegment_i.getIpEndI()))
                        && tTotalSegment_i.getIpType().equals(tTotalSegment_j.getIpType())) {
                    throw new IllegalArgumentException(
                            ERRORINFO + "<br/> 第" + (i + 2) + "行IP与第" + (j + 2) + "行IP数据重叠。");
                }
            }
        }
        return "";
    }

    // 处理X.X.X.X/X
    // 设置转换IP为整形
    // 转换数据
    private List<TTotalSegment> getTotalSegmentList(List<TTotalSegment> tTotalSegmentList, SysUser user) {
        String parentId = user.getDept().getParentId() + "";
        String city = "";
        if (CacheKitUtil.ip_dept != null && StrUtil.isNotEmpty(parentId) && !"null".equals(parentId)) {
            city = CacheKitUtil.ip_dept.get(parentId + "");
        }
        Date date = new Date();
        List<TTotalSegment> rList = tTotalSegmentList;
        for (int i = 0; i < rList.size(); i++) {

            try {
                TTotalSegment ts = rList.get(i);
                if (ts.getIpStart().contains("/") && StrUtil.isEmpty(ts.getIpEnd())) {
                    String[] ips = ts.getIpStart().split("/");
                    ts.setIpStart(ips[0].trim());
                    ts.setIpStartI(NetUtil.ipv4ToLong(ips[0].trim()));
                    ts.setIpEndI(Ipv4Util.getEndIpLong(ips[0].trim(), Convert.toInt(ips[1])));
                    ts.setIpEnd(NetUtil.longToIpv4(ts.getIpEndI()));
                    ts.setIpEndI(NetUtil.ipv4ToLong(ts.getIpEnd()));
                } else {
                    ts.setIpStart(ts.getIpStart().trim());
                    ts.setIpEnd(ts.getIpEnd().trim());
                    ts.setIpStartI(NetUtil.ipv4ToLong(ts.getIpStart().trim()));
                    ts.setIpEndI(NetUtil.ipv4ToLong(ts.getIpEnd().trim()));
                }
                if (StrUtil.isEmpty(ts.getIpType()) || StrUtil.isEmpty(ip_type.get(ts.getIpType()))) {
                    throw new IllegalArgumentException("网络分类不正确!");
                }
                if (StrUtil.isEmpty(ts.getIpCity()) || StrUtil.isEmpty(ip_city.getKey(ts.getIpCity()))) {
                    throw new IllegalArgumentException("地市不正确!");
                }
                if (StrUtil.isNotEmpty(city) && city.equals(StrUtil.isEmpty(ip_city.getKey(ts.getIpCity())))) {
                    throw new IllegalArgumentException("不能导入其它地市的数据!");
                }
                if (StrUtil.isNotEmpty(ts.getIpStatus()) && StrUtil.isEmpty(ip_status.getKey(ts.getIpStatus()))) {
                    throw new IllegalArgumentException("使用状态不正确!");
                }

//                if (!UserUtils.isRole(CacheKitUtil.ip_type.get(ts.getIpType()))) {
//                    throw new IllegalArgumentException("网络类型权限不正确，没有该类型：" + ts.getIpType() + "权限");
//                }

                if (StrUtil.isEmpty(ts.getIpStatus())) {
                    ts.setIpStatus("on");
                } else {
                    ts.setIpStatus(ip_status.getKey(ts.getIpStatus()));
                }
//                ts.setIpType(ip_type.getKey(ts.getIpType()));
                ts.setIpCity(ip_city.getKey(ts.getIpCity()));
                ts.setCreateBy(user.getNickName());
                ts.setCreateTime(date);

            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException(ERRORINFO + "<br/> 第" + (i + 2) + "行，格式不正确！" + e.getMessage());
            }
        }

        return rList;
    }
}